package link.anycar.study.java8.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class LoopModel {

    public static void main(String[] args) {
        LoopModel loopModel = new LoopModel();
        // Will multiple operations on a stream execute in different loops? Of course not!
        loopModel.multiOperations1();
        loopModel.multiOperations2();
        loopModel.multiOperations3();
        loopModel.multiOperations4();
    }

    private void printSeparator(int index) {
        String caller = Thread.currentThread().getStackTrace()[2].getMethodName();
        System.out.println("\n==========" + caller + ": " + index + "==========");
    }

    Stream<String> makeSample() {
        List<String> srcs = Arrays.asList("abc1", "abc", "2", "3b", "4", "5", "7", "11");
        return srcs.stream();
    }

    void multiOperations1() {
        printSeparator(0);
        makeSample().filter(x -> {
            System.out.println("First, the filter operation.");
            try {
                Integer.parseInt(x);
                return true;
            } catch (Exception e) {}
            return false;
        }).map(x -> {
            System.out.println("Second, transform strings to integer.");
            return Integer.parseInt(x); // No need to test here as non parsable integer has already been filtered out.
        }).forEach(x -> {
            System.out.println("Well, only an empty loop here.");
        });
    }

    void multiOperations2() {
        printSeparator(0);
        Integer reduce = makeSample().filter(x -> {
            System.out.println("First, the filter operation.");
            try {
                Integer.parseInt(x);
                return true;
            } catch (Exception e) {
            }
            return false;
        }).map(x -> {
            System.out.println("Second, transform strings to integer.");
            return Integer.parseInt(x);
        }).reduce(0, (x, y) -> {
            System.out.println("Third, reducing.");
            return x + y;
        });
        System.out.println(reduce);
    }

    void multiOperations3() {
        printSeparator(0);
        Optional<String> first = makeSample().filter(x -> {
            System.out.println("First, the filter operation.");
            try {
                Integer.parseInt(x);
                return true;
            } catch (Exception e) {
            }
            return false;
        }).findFirst();
        System.out.println(first.orElse(null));
    }

    void multiOperations4() {
        printSeparator(0);
        Integer reduced = makeSample().filter(x -> {
            System.out.println("First, the filter operation.");
            try {
                Integer.parseInt(x);
                return true;
            } catch (Exception e) {
            }
            return false;
        }).sorted().map(x -> {
            System.out.println("Second, transform strings to integer.");
            return Integer.parseInt(x);
        }).reduce(0, (x, y) -> {
            System.out.println("Third, reducing.");
            return x + y;
        });
        System.out.println(reduced);
        Optional<String> opt = Optional.of("hello");
    }
}